<?php
/**
 * IP地理位置查询类
 *
 * @author liang<lang@vip.deyi.com>
 * @since   2016/1/9 10:27
 * @copyright  deyi.com
 */

namespace Deyi\Functions;

define('__IPDAT__', ROOT_PATH . "/data/ipdata/17monipdb.dat");

class IPQuery
{
    private static $ip = null;

    private static $fp = null;
    private static $offset = null;
    private static $index = null;

    private static $cached = array();

    public static function find($ip)
    {
        if (empty($ip) === true) {
            return 'N/A';
        }

        if ($pos = strpos($ip, ',')) {
            $ip = substr($ip, 0, $pos);
        }

        $nip = gethostbyname($ip);
        $ipdot = explode('.', $nip);

        if ($ipdot[0] < 0 || $ipdot[0] > 255 || count($ipdot) !== 4) {
            return 'N/A';
        }

        if (isset(self::$cached[$nip]) === true) {
            return self::$cached[$nip];
        }

        if (self::$fp === null) {
            self::init();
        }

        $nip2 = pack('N', ip2long($nip));

        $tmp_offset = (int)$ipdot[0] * 4;
        $start = unpack('Vlen', self::$index[$tmp_offset] . self::$index[$tmp_offset + 1] . self::$index[$tmp_offset + 2] . self::$index[$tmp_offset + 3]);

        $index_offset = $index_length = null;
        $max_comp_len = self::$offset['len'] - 1024 - 4;
        for ($start = $start['len'] * 8 + 1024; $start < $max_comp_len; $start += 8) {
            if (self::$index{$start} . self::$index{$start + 1} . self::$index{$start + 2} . self::$index{$start + 3} >= $nip2) {
                $index_offset = unpack('Vlen', self::$index{$start + 4} . self::$index{$start + 5} . self::$index{$start + 6} . "\x0");
                $index_length = unpack('Clen', self::$index{$start + 7});

                break;
            }
        }

        if ($index_offset === null) {
            return 'N/A';
        }

        fseek(self::$fp, self::$offset['len'] + $index_offset['len'] - 1024);

        self::$cached[$nip] = explode("\t", fread(self::$fp, $index_length['len']));

        return self::$cached[$nip];
    }

    private static function init()
    {
        if (self::$fp === null) {
            self::$ip = new self();

            self::$fp = fopen(__IPDAT__, 'rb');
            if (self::$fp === false) {
                throw new \Exception('Invalid 17monipdb.dat file!');
            }

            self::$offset = unpack('Nlen', fread(self::$fp, 4));
            if (self::$offset['len'] < 4) {
                throw new \Exception('Invalid 17monipdb.dat file!');
            }

            self::$index = fread(self::$fp, self::$offset['len'] - 4);
        }
    }

    /**
     * 获取IP地理位置名称
     * @version APP 6.3.5
     * @author lang@vip.deyi.com
     * @param $ip
     * @return string
     */
    public static function getAreaNameByIp($ip)
    {
        $ipInfo = self::find($ip);

        if (is_array($ipInfo)) {
            return implode('', array_unique($ipInfo));
        }

        return '火星';
    }
}
